﻿using System;
using System.Linq;
using System.Web.UI.WebControls;

namespace N2.Details
{
	using Engine;

	/// <summary>
	/// Allows edit a statically typed member property of type <c cref="System.Type"/>
	///  with a <c cref="System.Web.UI.WebControls.DropDownList"/> control,
	///  populated with a list of descendants of a given type.
	/// </summary>
	[AttributeUsage(AttributeTargets.Property)]
	public class EditableTypeListAttribute : EditableDropDownAttribute
	{
		public Type BaseListItemType { get; set; }

		/// <summary>
		/// Instantiate the attribute.
		/// </summary>
		/// <param name="title">Caption to draw before the drop down list</param>
		/// <param name="sortOrder">Order on the edit form</param>
		/// <param name="baseListItemType">The type, which descendants to populate the drop down list with.</param>
		public EditableTypeListAttribute(string title, int sortOrder, Type baseListItemType)
			: base(title, sortOrder)
		{
			this.BaseListItemType = baseListItemType;
		}

		protected override ListItem[] GetListItems()
		{
			return (
				from _type in this.Engine.Resolve<ITypeFinder>().Find(this.BaseListItemType)
				where !_type.IsAbstract && !_type.ContainsGenericParameters
				select new ListItem(
					_type.FullName,
					GetFullyQualifiedTypeName(_type))
			).ToArray();
		}

		//DropDownList can only hold strings, so we need to convert System.Type back and forth
		protected override object GetValue(ListControl ddl)
		{
			return Utility.TypeFromName((string)base.GetValue(ddl));
		}

		protected override string GetValue(ContentItem item)
		{
			return GetFullyQualifiedTypeName(item[Name] as Type);
		}

		static string GetFullyQualifiedTypeName(Type type)
		{
			return null != type
				? type.AssemblyQualifiedName
				: string.Empty;
		}
	}
}
